﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MyDelegate
{
    public class DelegateExtension
    {
        public static void Show()
        {
            
            {
                {
                    InvokeAction action = new InvokeAction();
                    action.ExeMethod();
                    //想要去在Invoke.Show方法前后，扩展一些业务逻辑；
                    Console.WriteLine("===========================================================");
                    Action action1 = new Action(action.ExeMethod);
                    //再定义委托 
                    Func<Action, Action> action2 = new Func<Action, Action>(ExecNextMethod001);
                    //Action action3=  action2.Invoke(action1);
                    action1 = action2.Invoke(action1);



                    Func<Action, Action> action3 = new Func<Action, Action>(ExecNextMethod002);
                    //Action action4=   action3.Invoke(action1);
                    action1 = action3.Invoke(action1);

                    Func<Action, Action> action5 = new Func<Action, Action>(ExecNextMethod003);
                    action1 = action5.Invoke(action1);

                    Func<Action, Action> action6 = new Func<Action, Action>(ExecNextMethod004);
                    action1 = action6.Invoke(action1);

                    action1.Invoke();
                }

                //诉求：
                //我希望无限制的 增加扩展业务逻辑；
                //再增加一个--定义方法，通过委托包装后去当做参数传递；

                //1.已经做到了职责的单一；
                //2.但是当前这个 DelegateExtension.Show 方法不太稳定，如果要增加一环，我需要修改DelegateExtension.Show方法；


                //思路：可以把要执行的业务逻辑----特性--封装到特性中去； 
                {
                    Console.WriteLine("===========================================================");
                    InvokeAction1 invokeaction = new InvokeAction1();
                    Type type = typeof(InvokeAction1);
                    MethodInfo method = type.GetMethod("ExeMethod");

                    ExecNextMethod001Attribute attribute1 = method.GetCustomAttribute<ExecNextMethod001Attribute>();
                    Action action = new Action(() => { method.Invoke(invokeaction, null); });
                    action = attribute1.Do(action);


                    ExecNextMethod002Attribute attribute2 = method.GetCustomAttribute<ExecNextMethod002Attribute>();
                    action = attribute2.Do(action);


                    ExecNextMethod003Attribute attribute3 = method.GetCustomAttribute<ExecNextMethod003Attribute>();
                    action = attribute3.Do(action);

                    ExecNextMethod004Attribute attribute4 = method.GetCustomAttribute<ExecNextMethod004Attribute>();
                    action = attribute4.Do(action);

                    action.Invoke();
                }

                //思路：因为类型不一样，所以只能一个一个的判断；
                //如果能一次获取所有特性(矛盾，类型不一样，没有办法一次获取所有；？？？？统一类型，如何统一类型？？ 来一个父类，让特性继承父类，然后在获取特性的时候，通过父类获取；)：放在一个集合中，要逐个的调用特性的Do方法来包装委托的话，就可以循环执行；
                {
                    Console.WriteLine("===========================================================");
                    InvokeAction1 invokeaction = new InvokeAction1();
                    Type type = typeof(InvokeAction1);
                    MethodInfo method = type.GetMethod("ExeMethod");

                    Action action = new Action(() => { method.Invoke(invokeaction, null); });

                    IEnumerable<ExecNextMethodAbstractAttribute> attributellist = method.GetCustomAttributes<ExecNextMethodAbstractAttribute>();

                    foreach (var attribute in attributellist.Reverse())//调了一下顺序，不然的话是从下往上执行的 6  5  4  3  2  1
                    {
                        action = attribute.Do(action);
                    }
                    action.Invoke();
                }

                //这样就可以让我们自己在搭建框架的时候（支持了业务的扩展---AOP扩展---装饰器模式的番外篇），可以让程序员在使用我们这个框架的时候，更加聚焦业务逻辑；

                //可以动态增加业务逻辑；
                //有bug: 特性的标记---1/2/3.。。。逐个标记，但是执行的时候，执行的是 从上往下
                //Why?
            }
        }


        

        public static void ExecNextMethod(Action action)
        {
            Console.WriteLine("Exe method Before");
            action.Invoke();
            Console.WriteLine("Exe method After");
        }

        public static Action ExecNextMethod001(Action action)
        {

            return new Action(() =>
            {
                Console.WriteLine("Exe ExecNextMethod001 Start");
                action.Invoke();
                Console.WriteLine("Exe ExecNextMethod001 End");
            });
        }

        public static Action ExecNextMethod002(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("Exe ExecNextMethod002 Start");
                action.Invoke();
                Console.WriteLine("Exe ExecNextMethod002 End");
            });
        }

        public static Action ExecNextMethod003(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("Exe ExecNextMethod003 Start");
                action.Invoke();
                Console.WriteLine("Exe ExecNextMethod003 End");
            });
        }

        public static Action ExecNextMethod004(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("Exe ExecNextMethod004 Start");
                action.Invoke();
                Console.WriteLine("Exe ExecNextMethod004 End");
            });
        }
    }

    /// <summary>
    /// 这里是我们想要执行的业务逻辑
    /// </summary> 
    public class InvokeAction
    {
        public void ExeMethod()
        {
            Console.WriteLine("Exec ExeMethod");
        }
    }



    /// <summary>
    /// 这里是我们想要执行的业务逻辑
    /// </summary> 
    public class InvokeAction1
    {
        [ExecNextMethod001Attribute]
        [ExecNextMethod002Attribute]
        [ExecNextMethod003Attribute]
        [ExecNextMethod004Attribute]
        [ExecNextMethod005Attribute]
        [ExecNextMethod006Attribute]
        public void ExeMethod()
        {
            Console.WriteLine("Exec ExeMethod");
        }
    }

    public abstract class ExecNextMethodAbstractAttribute : Attribute
    {
        public abstract Action Do(Action action);

    }


    [AttributeUsage(AttributeTargets.Method)]
    public class ExecNextMethod001Attribute : ExecNextMethodAbstractAttribute// Attribute
    {
        public override Action Do(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("ExecNextMethod001Attribute ExecNextMethod001 Start");
                action.Invoke();
                Console.WriteLine("ExecNextMethod001Attribute ExecNextMethod001 End");
            });
        }
    }

    [AttributeUsage(AttributeTargets.Method)]
    public class ExecNextMethod002Attribute : ExecNextMethodAbstractAttribute// Attribute
    {
        public override Action Do(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("ExecNextMethod002Attribute ExecNextMethod002 Start");
                action.Invoke();
                Console.WriteLine("ExecNextMethod002Attribute ExecNextMethod002 End");
            });
        }
    }

    [AttributeUsage(AttributeTargets.Method)]
    public class ExecNextMethod003Attribute : ExecNextMethodAbstractAttribute// Attribute
    {
        public override Action Do(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("ExecNextMethod003Attribute ExecNextMethod003 Start");
                action.Invoke();
                Console.WriteLine("ExecNextMethod003Attribute ExecNextMethod003 End");
            });
        }
    }


    [AttributeUsage(AttributeTargets.Method)]
    public class ExecNextMethod004Attribute : ExecNextMethodAbstractAttribute// Attribute
    {
        public override Action Do(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("ExecNextMethod004Attribute ExecNextMethod004 Start");
                action.Invoke();
                Console.WriteLine("ExecNextMethod004Attribute ExecNextMethod004 End");
            });
        }
    }


    [AttributeUsage(AttributeTargets.Method)]
    public class ExecNextMethod005Attribute : ExecNextMethodAbstractAttribute// Attribute
    {
        public override Action Do(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("ExecNextMethod005Attribute ExecNextMethod005 Start");
                action.Invoke();
                Console.WriteLine("ExecNextMethod005Attribute ExecNextMethod005 End");
            });
        }
    }

    //1.增加特性，必须要继承ExecNextMethodAbstractAttribute---就是实现业务逻辑
    //2.标记注册
    public class ExecNextMethod006Attribute : ExecNextMethodAbstractAttribute
    {
        public override Action Do(Action action)
        {
            return new Action(() =>
            {
                Console.WriteLine("ExecNextMethod006Attribute ExecNextMethod006 Start");
                action.Invoke();
                Console.WriteLine("ExecNextMethod006Attribute ExecNextMethod006 End");
            });
        }
    }
}
